﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using Abp.Domain.Services;
using Abp.UI;
using Alipay.AopSdk.AspnetCore;
using Alipay.AopSdk.Core;
using Alipay.AopSdk.Core.Domain;
using Alipay.AopSdk.Core.Request;
using Alipay.AopSdk.Core.Util;
using Alipay.AopSdk.F2FPay.AspnetCore;
using Alipay.AopSdk.F2FPay.Business;
using Alipay.AopSdk.F2FPay.Domain;
using Alipay.AopSdk.F2FPay.Model;
using AVISOutBound.SSOServer.Payment.Alipay;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using MyCompanyName.AbpZeroTemplate.Configuration;

namespace AVISOutBound.SSOServer.Payment
{
    /// <summary>
    /// 支付宝的领域服务
    /// </summary>
    public class AlipayManager:DomainService,IAlipayManager
    {
        private IAlipayService _alipayService;
        private IAlipayF2FService _alipayF2FService;
        //private IAopClient _aopClient;
        //private AlipayOptions _options;

        public AlipayManager(IAlipayService alipayService, IAlipayF2FService alipayF2FService)
        {
            _alipayService = alipayService;
            _alipayF2FService = alipayF2FService;
        }

        ///// <summary>
        ///// 初始化配置
        ///// </summary>
        //private async void InitOptions()
        //{
        //    if (_options != null)
        //    {
        //        return;
        //    }
        //    _options = new AlipayOptions()
        //    {
        //        AlipayPublicKey = await SettingManager.GetSettingValueAsync(AppSettings.PaymentConfig.Alipay.PublicKey),
        //        AppId = await SettingManager.GetSettingValueAsync(AppSettings.PaymentConfig.Alipay.Appid),
        //        CharSet = await SettingManager.GetSettingValueAsync(AppSettings.PaymentConfig.Alipay.Charset),
        //        Gatewayurl = await SettingManager.GetSettingValueAsync(AppSettings.PaymentConfig.Alipay.Url),
        //        PrivateKey = await SettingManager.GetSettingValueAsync(AppSettings.PaymentConfig.Alipay.PrivateKey),
        //        SignType = await SettingManager.GetSettingValueAsync(AppSettings.PaymentConfig.Alipay.Sign_type),
        //        Uid = await SettingManager.GetSettingValueAsync(AppSettings.PaymentConfig.Alipay.Ppid)
        //    };
        //}

        ///// <summary>
        ///// 获取支付宝客户端
        ///// </summary>
        ///// <returns></returns>
        //private IAopClient GetClient()
        //{
        //    InitOptions();

        //    return _aopClient ?? (_aopClient = new DefaultAopClient(_options.Gatewayurl, _options.AppId,
        //               _options.PrivateKey, "json", "1.0",
        //               _options.SignType, _options.AlipayPublicKey, _options.CharSet, _options.IsKeyFromFile));
        //}

        #region QrCodePay(二维码支付)

        /// <summary>
        /// 二维码支付
        /// </summary>
        /// <param name="subject">订单标题</param>
        /// <param name="body">订单描述</param>
        /// <param name="orderAmount">订单金额。单位：分</param>
        /// <param name="outTradeNo">外部订单号，商户网站订单系统中唯一的订单号</param>
        /// <param name="notifyUrl">支付完成异步通知接收地址</param>
        /// <returns></returns>
        public string QrCodePay(string subject, string body, string orderAmount, string outTradeNo,string notifyUrl)
        {
            // 暂不支持配置
            AlipayTradePrecreateContentBuilder builder = BuildPrecreatContent(subject, body,orderAmount, outTradeNo);
            //商户接收异步通知的地址
            AlipayF2FPrecreateResult preCreateResult = _alipayF2FService.TradePrecreate(builder, notifyUrl);
            string qrCode = string.Empty;
            switch (preCreateResult.Status)
            {
                case ResultEnum.SUCCESS:
                    qrCode = preCreateResult.response.QrCode;
                    break;
                case ResultEnum.FAILED:
                    throw new UserFriendlyException("错误", "生成二维码失败:" + preCreateResult.response.Body);
                case ResultEnum.UNKNOWN:
                    throw new UserFriendlyException("错误", "生成二维码失败:" + (preCreateResult.response == null ? "配置或网络异常，请检查后重试" : "系统异常，请更新外部订单后重新发起请求"));
            }

            return qrCode;
        }

        /// <summary>
        /// 构建支付请求数据
        /// </summary>
        /// <param name="orderName">订单名称</param>
        /// <param name="body">订单描述</param>
        /// <param name="orderAmount">订单金额</param>
        /// <param name="outTradeNo">订单编号</param>
        /// <returns></returns>
        private AlipayTradePrecreateContentBuilder BuildPrecreatContent(string orderName, string body, string orderAmount,
            string outTradeNo)
        {
            // 线上联调时，请输入真实的外部单号
            if (string.IsNullOrEmpty(outTradeNo))
            {
                outTradeNo = DateTime.Now.ToString("yyyyMMddHHmmss") + "0000" +
                             (new Random()).Next(1, 10000).ToString();
            }
            AlipayTradePrecreateContentBuilder builder = new AlipayTradePrecreateContentBuilder();
            // 收款账号
            builder.seller_id = "2088031973435294";
            // 订单编号
            builder.out_trade_no = outTradeNo;
            // 订单总金额，单位：元
            builder.total_amount = orderAmount;
            // 参与优惠计算的金额
            //builder.discountable_amount = "";
            // 不参与优惠计算的金额
            //builder.undiscountable_amount = "";
            // 订单名称
            builder.subject = orderName;
            // 自定义超时时间
            builder.timeout_express = "5m";
            // 订单描述
            builder.body = body;
            // 门店编号，很重要的参数，可以用作之后的营销
            //builder.store_id = "";
            // 操作员编号，很重要的参数，可以用作之后的营销
            builder.operator_id = "2018041902582051";

            return builder;
        }


        #endregion

        #region WapPay(手机网站支付)

        /// <summary>
        /// 手机网站支付
        /// </summary>
        /// <param name="subject">订单标题</param>
        /// <param name="body">订单描述</param>
        /// <param name="orderAmount">订单金额。单位：元</param>
        /// <param name="outTradeNo">外部订单号，商户网站订单系统中唯一的订单号</param>
        /// <param name="returnUrl">支付完成后同步回调地址</param>
        /// <param name="notifyUrl">支付完成异步通知接收地址</param>
        /// <param name="timeoutExpress">该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。 该参数数值不接受小数点， 如 1.5h，可转换为 90m</param>
        /// <returns></returns>
        public async Task<string> WapPay(string subject, string body, string orderAmount, string outTradeNo,string returnUrl,string notifyUrl, string timeoutExpress = "5m")
        {
            AlipayTradeWapPayModel model = new AlipayTradeWapPayModel
            {
                Body = body,
                Subject = subject,
                TotalAmount = orderAmount,
                OutTradeNo = outTradeNo,
                ProductCode = "QUICK_WAP_WAY",
                TimeoutExpress = timeoutExpress,
            };

            AlipayTradeWapPayRequest request=new AlipayTradeWapPayRequest();
            // 设置同步回调地址
            request.SetReturnUrl(returnUrl);
            // 设置异步通知地址
            request.SetNotifyUrl(notifyUrl);
            // 将业务model载入到request
            request.SetBizModel(model);
            var response = _alipayService.SdkExecute(request);

            Debug.WriteLine($"Wap网站-订单支付发起成功，订单号:{outTradeNo}");

            return response.Body;
        }

        #endregion

        #region PcPay(PC网站支付)

        /// <summary>
        /// PC网站支付
        /// </summary>
        /// <param name="subject">订单标题</param>
        /// <param name="body">订单描述</param>
        /// <param name="orderAmount">订单金额。单位：元</param>
        /// <param name="outTradeNo">外部订单号，商户网站订单系统中唯一的订单号</param>
        /// <param name="returnUrl">支付完成后同步回调地址</param>
        /// <param name="notifyUrl">支付完成异步通知接收地址</param>
        /// <param name="timeoutExpress">该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。 该参数数值不接受小数点， 如 1.5h，可转换为 90m</param>
        /// <returns></returns>
        public async Task<string> PcPay(string subject, string body, string orderAmount, string outTradeNo, string returnUrl,
            string notifyUrl,string timeoutExpress="5m")
        {
            AlipayTradePagePayModel model = new AlipayTradePagePayModel
            {
                Body = body,
                Subject = subject,
                TotalAmount = orderAmount,
                OutTradeNo = outTradeNo,
                ProductCode = "FAST_INSTANT_TRADE_PAY",
                TimeoutExpress = timeoutExpress
            };


            AlipayTradePagePayRequest request=new AlipayTradePagePayRequest();
            // 设置同步回调地址
            request.SetReturnUrl(returnUrl);
            // 设置异步通知地址
            request.SetNotifyUrl(notifyUrl);
            // 将业务model载入到request
            request.SetBizModel(model);

            var response = _alipayService.SdkExecute(request);
            Debug.WriteLine($"PC网站-订单支付发起成功，订单号:{outTradeNo}");

            return response.Body;
        }

        #endregion

        #region ParseNotify(支付回调)

        /// <summary>
        /// 处理支付宝支付回调内容
        /// </summary>
        /// <param name="context">Http上下文</param>
        /// <returns></returns>
        public AlipayPayReceive ParseNotify(HttpContext context)
        {
            var dict = GetRequestPost(context);
            AlipayPayReceive receive = new AlipayPayReceive();
            if (dict.Count != 0)
            {
                //bool flag = RsaCheckV1(dict);
                bool flag = _alipayService.RSACheckV1(dict);
                if (flag)
                {
                    receive.OutTradeNo = dict["out_trade_no"];
                    receive.TradeNo = dict["trade_no"];
                    receive.IsSuccess = true;
                }
            }
            return receive;
        }

        ///// <summary>
        ///// RSA检查
        ///// </summary>
        ///// <param name="data">字典数据</param>
        ///// <returns></returns>
        //private bool RsaCheckV1(Dictionary<string, string> data)
        //{
        //    InitOptions();
        //    return AlipaySignature.RSACheckV1(data, _options.AlipayPublicKey, _options.CharSet, _options.SignType, false);
        //}

        /// <summary>
        /// 解析Get请求参数
        /// </summary>
        /// <param name="context">Http上下文</param>
        /// <returns></returns>
        private Dictionary<string, string> GetRequestGet(HttpContext context)
        {
            var dict = new Dictionary<string, string>();
            ICollection<string> requestItem = context.Request.Query.Keys;
            foreach (var item in requestItem)
            {
                dict.Add(item, context.Request.Query[item]);
            }

            return dict;
        }

        /// <summary>
        /// 解析Post请求参数
        /// </summary>
        /// <param name="context">Http上下文</param>
        /// <returns></returns>
        private Dictionary<string, string> GetRequestPost(HttpContext context)
        {
            var dict = new Dictionary<string, string>();
            ICollection<string> requestItem = context.Request.Form.Keys;
            foreach (var item in requestItem)
            {
                dict.Add(item, context.Request.Form[item]);
            }

            return dict;
        }

        #endregion

        #region Refund(支付退款)

        /// <summary>
        /// 支付退款
        /// </summary>
        /// <param name="tradeno">商户订单号</param>
        /// <param name="alipayTradeNo">支付宝交易号</param>
        /// <param name="refundAmount">退款金额。单位：元</param>
        /// <param name="refundReason">退款原因</param>
        /// <param name="refundNo">退款单号</param>
        public AlipayRefundResult Refund(string tradeno, string alipayTradeNo, string refundAmount, string refundReason,
            string refundNo)
        {
            AlipayRefundResult result=new AlipayRefundResult();

            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.OutTradeNo = tradeno;
            model.TradeNo = alipayTradeNo;
            model.RefundAmount = refundAmount;
            model.RefundReason = refundReason;
            model.OutRequestNo = refundNo;

            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            request.SetBizModel(model);

            var refundInfo = _alipayService.Execute(request);
            if (refundInfo.Code != "10000")
            {
                result.IsSuccess = false;
                result.ErrorMessage = refundInfo.Msg;
                return result;
            }

            result.OutTradeNo = refundInfo.OutTradeNo;
            result.TradeNo = refundInfo.TradeNo;
            result.IsSuccess = true;

            return result;
        }

        #endregion
    }
}
